package com.zhumo.sz.gaode;

import com.alibaba.fastjson.JSONObject;
import com.sun.xml.internal.ws.api.server.Adapter;
import com.zhumo.sz.config.AddressConfig;
import lombok.Data;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;

/**
 * @author zhumo
 * @time 2023-11-16
 * @comment 高德开放平台 api 用于地址的精准定位 每天的调用次数5000次 应用key:d4e5f719651859757fa03e09bbc5130b 通常使用这个
 */
@Data

public class GaoDeAddressProcessor {

    private String applicationKey; //应用key
    private HttpClient httpClient;  //应用同一个http客户端

    public static final String GaoDE_APPLICATION_KEY = "d4e5f719651859757fa03e09bbc5130b"; //默认key

    /**
     * 公用的poitype
     */
    public static final String PUBLIC_POI_TYPE ="公园|旅游景点|商场|购物中心|商务写字楼|政府及社会团体相关|政府机关相关|国家级机关及事业单位|住宅区|别墅|住宅小区|综合医院";

    /**
     * 单例
     * @param applicationKey 高德应用key
     */
    public GaoDeAddressProcessor(String applicationKey) {
        this.applicationKey = applicationKey;
        if (httpClient == null) {
            httpClient = HttpClients.createDefault();
        }
    }

    /**
     * 用于外部初始化使用
     */
    public static GaoDeAddressProcessor init(GaoDeAddressProcessor gaoDeAddressProcessor) {
        if (gaoDeAddressProcessor != null) {
            if (gaoDeAddressProcessor.getApplicationKey().length() != 32) {
                throw new IllegalArgumentException("高德应用key传递有误");
            }
        } else {
            //默认使用注册的应用key
            gaoDeAddressProcessor = new GaoDeAddressProcessor(GaoDE_APPLICATION_KEY);
        }
        return gaoDeAddressProcessor;
    }

    public GaoDeAddressProcessor() {}


    /**
     * 地址编码,大部分解析结果只能精确到区,根据传递的地址解析详细信息
     * @param address 地址
     * @param output 解析格式
     */
    public GaoDeGeoArea processGeocoAddress(String address, String output) {
        URI uri = null;
        try {
            uri = new URIBuilder(AddressConfig.GEOCODING_URL).
                    setParameter("key", applicationKey).
                    setParameter("address", address).
                    setParameter("output", output).build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        HttpGet httpGet = new HttpGet(uri);
        HttpEntity responseEntity = null;
        try {
            responseEntity = httpClient.execute(httpGet).getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = null;
        try {
            assert responseEntity != null;
            jsonObject = JSONObject.parseObject(EntityUtils.toString(responseEntity));
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert jsonObject != null;
        JSONObject detail = jsonObject.getJSONArray("geocodes").getJSONObject(0);
        //这里请求不到数据 有一定的记录报错 直接导致对应服务停止
        String[] locations = detail.getString("location").split(",");
        GaoDeGeoArea area = GaoDeGeoArea.builder().address(detail.getString("formatted_address"))
                .country(detail.getString("country")).city(detail.getString("city"))
                .adCode(detail.getString("adcode")).level(detail.getString("level"))
                .province(detail.getString("province")).cityCode(detail.getString("citycode"))
                .street(detail.getString("street")).district(detail.getString("district"))
                .lng(locations[0]).lat(locations[1]).build();
        area.setNeighborhood(detail.getString("neighborhood"));
        return area;
    }
    /**
     * @param locations  经纬度信息
     * @param radius 搜索半径
     * @param output 输出格式
     * 逆编码 根据传入的经纬度转换成详细地址及其周边街道信息,可以指定搜索半径
     * extensions 默认为base 设置为all为返回周边poi信息 周边道路,交叉口,建筑
     */
    public GaoDeResGeoArea processReverseCode(String locations,String radius,String output)  {
        URI uri = null;
        try {
            uri = new URIBuilder(AddressConfig.REVERSE_GEOCODING_URL).setParameter("key",applicationKey)
                    .setParameter("location",locations)
                    .setParameter("output",output)
                    .setParameter("radius",radius).build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        HttpGet httpGet = new HttpGet(uri);
        HttpEntity responseEntity = null;
        try {
            responseEntity = httpClient.execute(httpGet).getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert responseEntity != null;
        JSONObject detail = null;
        try {
            detail = JSONObject.parseObject(EntityUtils.toString(responseEntity)).getJSONObject("regeocode");
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject addressComponent = detail.getJSONObject("addressComponent");
        String[] locationsList = locations.split(",");
        GaoDeResGeoArea area = GaoDeResGeoArea.builder().adcode(addressComponent.getString("adcode")).
                country(addressComponent.getString("country")).province(addressComponent.getString("province"))
                .city(addressComponent.getString("city")).cityCode(addressComponent.getString("citycode"))
                .district(addressComponent.getString("district"))
                .town(addressComponent.getString("township")).townCode(addressComponent.getString("towncode"))
                .streetNumber(addressComponent.getString("streetNumber"))  //门牌信息
                .neighborhood(addressComponent.getString("neighborhood"))
                .lng(locationsList[0]).lat(locationsList[1])
                .building(addressComponent.getString("building"))
                .businessAreas(addressComponent.getJSONArray("businessAreas").toJSONString()).build();
        area.setAddress(detail.getString("formatted_address"));
        return area;
    }
    /**
     *
     * @param locations 经纬度坐标
     * @param extensions 详细程度
     * @param radius 搜索半径(米)
     * @param poiTypes poi类型
     * @param roadLevel 道路级别 传递1仅返回主干道
     * @param output 返回类型
     */
    public GaoDeResGeoArea processReverseCode(String locations,String extensions,String radius,String poiTypes,
                                     String roadLevel,String output)  {
        if (!"all".equals(extensions) && !"base".equals(extensions)){
            throw new IllegalArgumentException("extensions参数传递不合法,该参数必须为base或者all其中之一");
        }
        String[] locationsList = locations.split(",");
        if (locationsList.length != 2){
            throw new IllegalArgumentException("地址坐标传递不合法,该参数必须为 (lng,lat)的形式");
        }

        URI uri = null;
        try {
            uri = new URIBuilder(AddressConfig.REVERSE_GEOCODING_URL).setParameter("key",applicationKey)
                    .setParameter("location",locations)
                    .setParameter("output",output)
                    .setParameter("extensions",extensions)
                    .setParameter("poiTypes",poiTypes)
                    .setParameter("roadLevel",roadLevel)
                    .setParameter("radius",radius).build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        HttpGet httpGet = new HttpGet(uri);
        HttpEntity responseEntity = null;
        try {
            responseEntity = httpClient.execute(httpGet).getEntity();
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject detail = null;
        try {
            assert responseEntity != null;
            detail = JSONObject.parseObject(EntityUtils.toString(responseEntity)).getJSONObject("regeocode");
        } catch (IOException e) {
            e.printStackTrace();
            e.printStackTrace();
        }
        assert detail != null;
        JSONObject addressComponent = detail.getJSONObject("addressComponent");
        if (Objects.isNull(addressComponent)){
            return new GaoDeResGeoArea();
        }
        GaoDeResGeoArea area = GaoDeResGeoArea.builder().adcode(addressComponent.getString("adcode")).
                country(addressComponent.getString("country")).province(addressComponent.getString("province"))
                .city(addressComponent.getString("city")).cityCode(addressComponent.getString("citycode"))
                .district(addressComponent.getString("district"))
                .town(addressComponent.getString("township")).townCode(addressComponent.getString("towncode"))
                .streetNumber(addressComponent.getString("streetNumber"))  //门牌信息
                .neighborhood(addressComponent.getString("neighborhood"))
                .lng(locationsList[0]).lat((locationsList[1]))
                .building(addressComponent.getString("building"))
                .businessAreas((addressComponent.getJSONArray("businessAreas")).toJSONString()) //TODO
                .roads(detail.getString("roads"))
                .aois(detail.getString("aois")).pois(detail.getString("pois"))
                .build();
        area.setAddress(detail.getString("formatted_address"));
        return area;
    }

    // d4e5f719651859757fa03e09bbc5130b
//    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
//        GaoDeAddressProcessor gaoDeAddressProcessor = new GaoDeAddressProcessor("d4e5f719651859757fa03e09bbc5130b");
//        GaoDeGeoArea area = gaoDeAddressProcessor.processGeocoAddress("河北省保定市望都县祥和苑", "json");
//        System.out.println(area);
//
//        GaoDeResGeoArea resGeoArea = gaoDeAddressProcessor.processReverseCode("116.481488,39.990464", "1000", "json");
//        System.out.println(resGeoArea);
////
//        GaoDeResGeoArea areaDetail = gaoDeAddressProcessor.processReverseCode("116.481488,39.990464", "all", "1000",
//                "商务写字楼", "1", "json");
//        System.out.println(areaDetail.getAois());
//        System.out.println("------------------------------");
//        System.out.println(areaDetail.getPois());
//        /*
//        {"poiweight":"0.608688","businessarea":"望京","address":"阜通东大街6号",
//        "distance":"51.0778","name":"方恒国际","location":"116.482086,39.990496",
//        "tel":"010-84718888","id":"B000A837FH","type":"商务住宅;楼宇;商住两用楼宇","direction":"东"}
//
//        ,{"poiweight":"0.619523","businessarea":"望京","address":"阜通东大街6号院3号楼","distance":"100.977",
//        "name":"北京方恒假日酒店","location":"116.480979,39.989644",
//        "tel":"010-64733333","id":"B000A8URXB","type":"住宿服务;宾馆酒店;四星级宾馆","direction":"西南"}
//         */
//
//    }

}
